home *** CD-ROM | disk | FTP | other *** search
- Path: ix.netcom.com!netnews
- From: jlilley@ix.netcom.com (John Lilley)
- Newsgroups: comp.lang.c++
- Subject: Re: For Experts: How to load a DLL dynamically ?
- Date: 16 Mar 1996 16:35:30 GMT
- Organization: Netcom
- Message-ID: <4ieqki$dqv@cloner3.netcom.com>
- References: <4ibr0a$8f9@nms.telepost.no>
- NNTP-Posting-Host: den-co12-24.ix.netcom.com
- Mime-Version: 1.0
- Content-Type: Text/Plain; charset=US-ASCII
- X-NETCOM-Date: Sat Mar 16 8:35:30 AM PST 1996
- X-Newsreader: WinVN 0.99.7
-
- In article <4ibr0a$8f9@nms.telepost.no>, ca@sesam.dnv.no says...
- >
- >Hi everyone,
- >
- >I have a problem which I'm sure some of you experts can solve (???):
- >I'm using MSVC++ 4.0 under Windows NT 3.51.
- >
- >But what do I do if I have a DLL which export classes ? i.e.
- >
- >#ifdef DLL_IMPLEMENTATION
- > #define IMPORT_EXPORT _declspec(dllexport)
- >#else
- > #define IMPORT_EXPORT _declspec(dllimport)
- >#endif
- >
- >class IMPORT_EXPORT DLLfoo { // class exported from dll
- >public:
- > DLLfoo(); // constructor
- > int bar(); // some member function
- >private:
- > int value;
- >};
- >
- >In an application using the DLL, I want to:
- >
- > DLLfoo foo; // create object from DLL class DLLfoo
- > int somevalue = foo.bar(); // call member function of that class
-
-
- Funny you should ask, I just did this yesterday...
-
- There are several levels to the problem. Note that this only applies to
- what you want to do, which is dynamic loading and binding. Static
- binding of DLLs is easy.
-
- The first problem is that since the methods are loaded at runtime, you
- can never create and destroy an object of this class! At least not
- directly. In other words, you could not write:
- DLLfoo f;
- because the constructor for foo is unavailable, AND you're not allowed
- to call it explicitly. So I would write a static member to create and destroy
- DLLfoos. Note that limits the use of foo to heap allocation, but that is
- necessary because there is no dynamic loading of the constructor of the class.
- So change class DLLfoo. I'd remove the class export, because it does you
- no good anyway, and just export the create/destroy methods.
-
- #define EXPORT __declspec(dllexport)
- class DLLfoo {
- static EXPORT DLLfoo* Create(/*args*/); // create a foo
- static EXPORT void Destroy(DLLfoo* foo); // destroy a foo
- ...
- };
-
-
- Which brings us to the second problem: How do you get ahold of the static methods?
- C++ methods are "decorated" or name-mangled, which means that you cannot just use
- "Create" and "Destroy" as the names passed to GetProcAddress(). Instead you need
- to use the decorated name, which look more like "?Create@DLLfoo@@SAPAV1@PAVDLLfoo@@@Z".
- To find the actual mangled names, compile the DLL and run DUMPBIN on it, and use
- the names that seem like the right ones. This is the other reason to only export
- the Create and Destroy methods, to avoid sifting over a zillion names in the
- DUMPBIN output.
-
-
- Now you can load the library and create a DLLfoo:
- typedef DLLfoo* (*CreateFooFP)(/*args*/);
- HINSTANCE hinstance = LoadLibrary("foo.dll");
- CreateFooFP createFoo = (CreateFooFP)GetProcAddress("MANGLED_NAME_GOES_HERE");
- DLLfoo* foo = createFoo(/*args*/);
-
- Note that you can substitute a function pointer for a method in this case
- only because the method is static. I'm not sure if this is "official" but
- it works.
-
- Now you've got a foo but can't DO anything with it, because you haven't imported the
- other methods. You could use the DUMPBIN procedure to get the mangled names for
- other methods, but I would use the following trick instead: Make all of the
- methods you want to use "virtual". This automatically binds them at runtime
- via the object vtable, so you don't need to load them or call them through a
- "pointer-to-object-method", which is ugly. You don't even need to export them.
- So your complete DLLfoo should be something like:
-
- // header
- #define EXPORT __declspec(dllexport)
- class DLLfoo {
- public:
- static EXPORT DLLfoo* Create(/*args*/); // create a foo
- static EXPORT void Destroy(DLLfoo* foo); // destroy a foo
- // all public methods are virtual
- virtual void method1(/*args*/);
- virtual int method2(/*args*/);
- ...
- private:
- // private methods can be non-virtual
- };
-
- // source
- DLLfoo* DLLfoo::Create(/*args*/) { return new DLLfoo(/*args*/); }
- void DLLfoo::Destroy(DLLfoo*foo) { delete foo; }
- void DLLfoo::method1(/*args*/) { ... }
- int DLLfoo::method2(/*args*/) { ... }
-
-
- Of course, you *still* cannot:
- 1) Create a DLLfoo on the stack
- 2) Copy a DLLfoo using a copy constructor or assignment operator.
- 3) Call new or delete directly on the class.
-
- All of this can prohibit it's use in container classes.
- If you need that, then create a "proxy" class on the application side
- that wrappers DLLfoo, creates a DLLfoo inside its constructor, etc:
-
- class AppFoo {
- public:
- AppFoo() { dllfoo = dllFooCreateFuncPtr(...); }
- ~AppFoo() { dllFooDestroyFuncPtr(dllfoo); }
- void method1(/*args*/) { doofoo->method1(/*args*/); }
- int method2(/*args*/) { return doofoo->method2(/*args*/); }
- private:
- DLLfoo* dllfoo;
- }
-
-
- Hope it helps. This is a nasty one but the solution is so (relatively) simple!
-
- john lilley
-
-
-
-